#ifndef REL_OP_H
#define REL_OP_H

#include <sstream>
#include "Pipe.h"
#include "DBFile.h"
#include "Record.h"
#include "Function.h"
#include <tr1/unordered_map>
#include <map>

void *SelectFileWorker(void* param);
void *SelectPipeWorker(void* param);
void *ProjectWorker(void* param);
void *SumWorker(void* param);
void *JoinWorker(void* param);
void *DuplicateRemovalWorker(void* param);
void *WriteOutWorker(void* param);
void *GroupByWorker(void* param);

class RelationalOp {
    protected:
        int nOfPages;

	public:
        // blocks the caller until the particular relational operator
        // has run to completion
        virtual void WaitUntilDone () = 0;

        // tell us how much internal memory the operation can use
        virtual void Use_n_Pages (int n) = 0;
};

class SelectFile : public RelationalOp {

	private:
        pthread_t thread;
        DBFile *in;
        Pipe *out;


	public:
        CNF *cnf;
        Record *buffer;

        void Run (DBFile &inFile, Pipe &outPipe, CNF &selOp, Record &literal);
        void WaitUntilDone ();
        void Use_n_Pages (int n);
        void DoWork();
};

class SelectPipe : public RelationalOp {

    private:
        pthread_t thread;
        Record *buffer;
        Pipe *in;
        Pipe *out;
        CNF *cnf;

	public:
        void Run (Pipe &inPipe, Pipe &outPipe, CNF &selOp, Record &literal);
        void WaitUntilDone ();
        void Use_n_Pages (int n);
        void DoWork();
};

class Project : public RelationalOp {

    private:
        pthread_t thread;
        int *keepMe;
        int numAttsInput;
        int numAttsOutput;
        Pipe *in;
        Pipe *out;

	public:
        void Run (Pipe &inPipe, Pipe &outPipe, int *keepMe, int numAttsInput, int numAttsOutput);
        void WaitUntilDone ();
        void Use_n_Pages (int n);
        void DoWork();
};

class Join : public RelationalOp {

	private:
        pthread_t thread;
        Record *buffer;
        CNF *cnf;
        Pipe *inL;
        Pipe *inR;
        Pipe *out;
        int joinType;

	public:
        void Run (Pipe &inPipeL, Pipe &inPipeR, Pipe &outPipe, CNF &selOp, Record &literal);
        void WaitUntilDone ();
        void Use_n_Pages (int n);
        void DoWork();
        void DoHardWork();
        void DoHashedWork(OrderMaker &omL, OrderMaker &omR);
};

class DuplicateRemoval : public RelationalOp {

	private:
        pthread_t thread;
        Schema *schema;
        Pipe *in;
        Pipe *out;

	public:
        void Run (Pipe &inPipe, Pipe &outPipe, Schema &mySchema);
        void WaitUntilDone ();
        void Use_n_Pages (int n);
        void DoWork();
};

class Sum : public RelationalOp {

     private:
        pthread_t thread;
        Pipe *in;
        Pipe *out;
        Function *func;

	public:
        void Run (Pipe &inPipe, Pipe &outPipe, Function &computeMe);
        void WaitUntilDone ();
        void Use_n_Pages (int n);
        void DoWork();
};

class GroupBy : public RelationalOp {

	private:
        pthread_t thread;
        Pipe *in;
        Pipe *out;
        OrderMaker *om;
        Function *func;

	public:
        void Run (Pipe &inPipe, Pipe &outPipe, OrderMaker &groupAtts, Function &computeMe);
        void WaitUntilDone ();
        void Use_n_Pages (int n);
        void DoWork();
};

class WriteOut : public RelationalOp {

	private:
        pthread_t thread;
        Pipe *in;
        FILE *out;
        Schema *schema;

	public:
        void Run (Pipe &inPipe, FILE *outFile, Schema &mySchema);
        void WaitUntilDone ();
        void Use_n_Pages (int n);
        void DoWork();
};

#endif
